home *** CD-ROM | disk | FTP | other *** search
/ MacTech 1 to 12 / MacTech-vol-1-12.toast / Source / MacTech® Magazine / Volume 06 - 1990 / 06.01 Jan 90 / Slider Source / drag.p next >
Encoding:
Text File  |  1988-06-22  |  12.4 KB  |  402 lines  |  [TEXT/MPS ]

  1.  
  2. {$R+}            { range checking }
  3.  
  4. UNIT Drag;
  5.  
  6.  
  7. INTERFACE
  8.  
  9. USES
  10.       MemTypes, QuickDraw, OSIntf, ToolIntf, SANE;
  11.  
  12. PROCEDURE DragIt;
  13.  
  14.  
  15. IMPLEMENTATION
  16.  
  17. CONST
  18.     nearInfinity    = 32000;
  19.     SlopSize        = 25;
  20.     OutOfBounds    = $8000;
  21.     allKeyEvents    = keyDownMask + keyUpMask + autoKeyMask;
  22.  
  23. TYPE
  24.     WindArray = ARRAY[1..32] OF WindowPtr;    {    this data structure stores the window pointers that
  25.                                                                             have been selected with the mouse. The first pointer
  26.                                                                             in the array (WindArray[1]) must be the pointer to
  27.                                                                             the selected window closest to the front window. }
  28.  
  29. PROCEDURE Get3Cursors (VAR svCrs: Cursor; VAR hndCrs: Cursor; VAR scndCrs: Cursor);    FORWARD;
  30. PROCEDURE GetScreenSize (topWind: windowPtr; VAR screenPerim: rect);                            FORWARD;
  31. FUNCTION LoadSound (VAR SoundBuffer: Ptr; VAR sndSize: longint): boolean;                        FORWARD;
  32. FUNCTION InsertWPtr(HitWPtr: windowPtr; VAR PtrArray: WindArray; VAR NumWind: integer): boolean;        FORWARD;
  33. PROCEDURE SumWRgnsBelow (StartWPtr: windowPtr; DragRegion: RgnHandle);                FORWARD;
  34. PROCEDURE MoveWindBelow (StartWPtr: windowPtr; hor, ver: integer; dragArea: rect);        FORWARD;
  35. PROCEDURE MoveWindSel (VAR PtrArray: WindArray; NumWind, hor, ver: integer; dragArea: rect);    FORWARD;
  36.  
  37.  
  38.  
  39. PROCEDURE DragIt;
  40.  
  41. VAR
  42.     theEvent                        : EventRecord;
  43.     WMgrPort, savePort        : GrafPtr;
  44.     HitWindPtr, topWindPtr    : WindowPtr;
  45.     currentWPeek                : windowPeek;
  46.     WPtrArray                    : WindArray;
  47.     DragRgn, ExistClipRgn    : RgnHandle;
  48.     mousePos                        : Point;
  49.     limitRect, slopRect        : rect;
  50.     screenBounds, dragLim    : rect;
  51.     thePart    , index                : integer;
  52.     NumWSel, vMov, hMov    : integer;
  53.     mainCursor, saveCursr    : Cursor;
  54.     secondCursor                : Cursor;
  55.     DropOut, haveSound        : boolean;
  56.     SoundPointer                : Ptr;
  57.     sndSize, longPos            : longint;
  58.  
  59. BEGIN
  60.     topWindPtr := FrontWindow;                    { this does not change }
  61.  
  62.     GetPort(savePort);                                { save state of port & clip }
  63.     DragRgn := NewRgn;
  64.     ExistClipRgn := NewRgn;
  65.     GetClip(ExistClipRgn);
  66.  
  67.     GetScreenSize (topWindPtr, screenBounds);    { get drag area size }
  68.     dragLim := screenBounds;
  69.     InsetRect (dragLim, 20, 0);
  70.  
  71.     GetWMgrPort(WMgrPort);
  72.     SetPort(WMgrPort);
  73.         
  74.     Get3Cursors (saveCursr, mainCursor, secondCursor);
  75.     SetCursor (mainCursor);
  76.     haveSound := LoadSound (SoundPointer, sndSize);
  77.  
  78.     NumWSel := 0;
  79.     DropOut := FALSE;
  80.     WPtrArray[1] := topWindPtr;    { init to prevent 'ClipAbove' call when no windows sel }
  81.  
  82.     REPEAT
  83.         IF GetNextEvent(mDownMask, theEvent) then begin
  84.             IF (haveSound)
  85.                 then StartSound (SoundPointer, sndSize, NIL);            { play asynchronous sound }
  86.             mousePos := theEvent.where;
  87.             thePart := FindWindow (theEvent.where, hitWindPtr);
  88.  
  89.             if (thePart < inSysWindow)
  90.                 then begin
  91.                     sysBeep (1);
  92.                     Dropout := TRUE;
  93.                     end
  94.                 else begin                                        { do setup of cursor and drag region }
  95.                     if (BitAnd(theEvent.modifiers, shiftKey) <> 0)
  96.                         then begin
  97.                             if (InsertWPtr(HitWindPtr, WPtrArray, NumWSel))
  98.                                 then begin
  99.                                     SetCursor (secondCursor);
  100.                                     currentWPeek := WindowPeek (HitWindPtr);
  101.                                     UnionRgn (currentWPeek^.StrucRgn, DragRgn, DragRgn);
  102.                                     end;
  103.                             end
  104.                         else begin
  105.                             Dropout := TRUE;
  106.                             if (BitAnd(theEvent.modifiers, optionKey) <> 0)
  107.                                 then begin
  108.                                     SetRectRgn (DragRgn, 0, 0, 0, 0);        { empty region of accumulated regions }
  109.                                     SumWRgnsBelow (hitWindPtr, DragRgn);
  110.                                     WPtrArray[1] := hitWindPtr;
  111.                                     end
  112.                                 else begin
  113.                                     if (NumWSel = 0)
  114.                                         then SumWRgnsBelow (topWindPtr, DragRgn)
  115.                                         else begin
  116.                                             if (InsertWPtr(HitWindPtr, WPtrArray, NumWSel))
  117.                                                 then begin
  118.                                                     SetCursor (secondCursor);
  119.                                                     currentWPeek := WindowPeek (HitWindPtr);
  120.                                                     UnionRgn (currentWPeek^.StrucRgn, DragRgn, DragRgn);
  121.                                                     end;
  122.                                             end;    { if (NumWSel > 0) }
  123.                                     end;
  124.                             end;        { end setup of drag region }
  125.  
  126.                     ClipRect(WMgrPort^.portRect);            { set current clipping }
  127.                     if (WPtrArray[1] <> topWindPtr)        { top selected window must be in 'WPtrArray[1]' }
  128.                         then ClipAbove (WindowPeek (WPtrArray[1]));
  129.  
  130.                     IF (BitAnd(theEvent.modifiers, cmdKey) <> 0)        { expand drag rect if Cmd key down }
  131.                         then SetRect (dragLim, -nearInfinity, -nearInfinity, nearInfinity, nearInfinity);
  132.                     with dragLim do begin
  133.                         SetRect (limitRect, left, top, right, bottom);
  134.                         SetRect (slopRect, left - SlopSize, top - 45, right + SlopSize, bottom + SlopSize);
  135.                         end;
  136.  
  137.                     longPos := DragGrayRgn (DragRgn, mousePos, limitRect, slopRect, 0, NIL);
  138.  
  139.                     IF (longPos <> OutOfBounds) then begin        { if drag returned OK, then move windows }
  140.                         hMov := LoWord (longPos);
  141.                         vMov := HiWord (longPos);
  142.                         IF (BitAnd(theEvent.modifiers, shiftKey) <> 0)
  143.                             then begin                                    { move on shift ONLY if moved more than 5 pixels }
  144.                                 IF (ABS (hMov) + ABS (vMov) > 5) then begin
  145.                                     Dropout := TRUE;
  146.                                     MoveWindSel (WPtrArray, NumWSel, hMov, vMov, dragLim);
  147.                                     end;
  148.                                 end
  149.                             else begin
  150.                                 IF (BitAnd(theEvent.modifiers, optionKey) <> 0)
  151.                                     then MoveWindBelow (hitWindPtr, hMov, vMov, dragLim)
  152.                                     else begin                            { default actions }
  153.                                         if (NumWSel = 0)
  154.                                             then MoveWindBelow (topWindPtr, hMov, vMov, dragLim)
  155.                                             else MoveWindSel (WPtrArray, NumWSel, hMov, vMov, dragLim);
  156.                                         end;
  157.                                 end;
  158.                         end;        { IF (longPos <> OutOfBounds) ... }
  159.                 end;        { if (thePart < inSysWindow)... }
  160.             SetCursor (mainCursor);
  161.             end;
  162.     UNTIL Dropout;
  163.  
  164.     IF (haveSound)
  165.         then DisposPtr (SoundPointer);
  166.     SetPort (savePort);                        { restore port & clipping }
  167.     SetClip (ExistClipRgn);
  168.     DisposeRgn (ExistClipRgn);            { dispose of regions }
  169.     DisposeRgn (DragRgn);
  170.     flushEvents (allKeyEvents, 0);        { in case the user re-selected the FKEY while we were in here }
  171.     SetCursor (saveCursr);                { restore cursor }
  172. END;
  173.  
  174.  
  175.  
  176.  
  177. PROCEDURE Get3Cursors (VAR svCrs: Cursor; VAR hndCrs: Cursor; VAR scndCrs: Cursor);
  178. CONST
  179.     LoMemCrsrLoc    = $844;
  180. VAR
  181.     CrsrPtr    : ^Cursor;
  182. BEGIN
  183.     CrsrPtr := pointer (LoMemCrsrLoc);
  184.     svCrs := CrsrPtr^;
  185.  
  186.     StuffHex (ptr (@hndCrs), 'AAAA0000B030334E' );
  187.     StuffHex (ptr (longint (@hndCrs) + 8), '84C954C982490249');
  188.     StuffHex (ptr (longint (@hndCrs) + 16), '8D01130091000800');
  189.     StuffHex (ptr (longint (@hndCrs) + 24), '8400040082004100');
  190.     StuffHex (ptr (longint (@hndCrs) + 32), 'AAAA0000B030337E');
  191.     StuffHex (ptr (longint (@hndCrs) + 40), '87FF57FF83FF03FF');
  192.     StuffHex (ptr (longint (@hndCrs) + 48), '8FFF1FFF9FFF0FFF');
  193.     StuffHex (ptr (longint (@hndCrs) + 56), '87FF07FF83FF41FF');
  194.     StuffHex (ptr (longint (@hndCrs) + 64), '00050007');
  195.  
  196.     StuffHex (ptr (@scndCrs), '000000000030034E' );
  197.     StuffHex (ptr (longint (@scndCrs) + 8), '04C904C902490249');
  198.     StuffHex (ptr (longint (@scndCrs) + 16), '0D01130011000800');
  199.     StuffHex (ptr (longint (@scndCrs) + 24), '0400040002000100');
  200.     StuffHex (ptr (longint (@scndCrs) + 32), '000000000030037E');
  201.     StuffHex (ptr (longint (@scndCrs) + 40), '07FF07FF03FF03FF');
  202.     StuffHex (ptr (longint (@scndCrs) + 48), '0FFF1FFF1FFF0FFF');
  203.     StuffHex (ptr (longint (@scndCrs) + 56), '07FF07FF03FF01FF');
  204.     StuffHex (ptr (longint (@scndCrs) + 64), '00050007');
  205. END;
  206.  
  207.  
  208.  
  209.  
  210. PROCEDURE GetScreenSize (topWind: windowPtr; VAR screenPerim: rect);
  211. TYPE
  212.     WStatePtr = ^WStateData;
  213.     WStateHdl = ^WStatePtr;
  214. VAR
  215.     windRect        : rect;
  216.     ZoomDataHdl    : WStateHdl;
  217.     tempWindPtr    : windowPtr;
  218. BEGIN
  219.     SetRect (windRect, 40, 0, 100, 100);
  220.     tempWindPtr := NewWindow (nil, windRect, 'x', FALSE, 8, topWind, TRUE, 0);
  221.     ZoomDataHdl := WStateHdl (WindowPeek (tempWindPtr)^.dataHandle);
  222.     screenPerim.left := ZoomDataHdl^^.stdState.left - 2;
  223.     screenPerim.top := ZoomDataHdl^^.stdState.top;
  224.     screenPerim.Right := ZoomDataHdl^^.stdState.right + 2;
  225.     screenPerim.Bottom := ZoomDataHdl^^.stdState.bottom + 2;
  226.     disposeWindow (tempWindPtr);
  227. END;
  228.  
  229.  
  230.  
  231.  
  232. FUNCTION LoadSound (VAR SoundBuffer: Ptr; VAR sndSize: longint): boolean;
  233.     { This code trys to load a sound file. To allow some selection of playback rate, it will look for 2
  234.       different files.  If it finds a file called Sound22, it will load/play it at a sampling rate of 22 kHz.
  235.       If thats not found, it will look for Sound11, and if found it will be played at 11 kHz.    }  
  236. VAR
  237.     FFSound        : FFSynthPtr;
  238.     soundRef        : integer;
  239.     rateDiv, rc    : integer;
  240.     Count, fSize    : longint;
  241. BEGIN
  242.     rateDiv := 1;        { assume 22 kHz sampling }
  243.     LoadSound := FALSE;
  244.     rc := FSOpen ('Sound22', 0, soundRef);
  245.     IF (rc <> noErr) THEN BEGIN
  246.         rateDiv := 2;        { set for 11 kHz playback }
  247.         rc := FSOpen ('Sound11', 0, soundRef);
  248.         END;
  249.         
  250.     IF (rc = noErr)
  251.         THEN BEGIN
  252.             LoadSound := TRUE;
  253.             rc := GetEOF( soundRef, fSize );    { get file size }
  254.             sndSize := fSize + 6;                { size of sound buffer }
  255.             SoundBuffer := NewPtr (sndSize);
  256.             FFSound := FFSynthPtr (SoundBuffer);
  257.             FFSound^.mode := ffMode;                                { free form synthesizer }
  258.             FFSound^.count := FixRatio (1, rateDiv);            { fill in the fixed binary playback rate }
  259.             Count := fSize;
  260.             rc := FSRead (soundREf, Count, @FFSound^.waveBytes);
  261.             rc := FSClose (soundRef);
  262.             END;
  263. END;
  264.  
  265.  
  266.  
  267. FUNCTION InsertWPtr(HitWPtr            : windowPtr;
  268.                                 VAR PtrArray    : WindArray;
  269.                                 VAR NumWind    : integer): boolean;
  270. {    purpose     IF ptr not in list, put window ptr 'HitWPtr' in list 'PtrArray' & add 1 to 'NumWind'
  271.                     ALWAYS keep ptr to highest selected window in 'PtrArray[1]'    }
  272. VAR
  273.     ctr        : integer;
  274.     match    : boolean;
  275.     cWPeek    : windowPeek;
  276.     cWPtr    : WindowPtr;
  277.     HiPtr    : WindowPtr;
  278. BEGIN
  279.     if (NumWind = 0)
  280.         then begin
  281.             NumWind := 1;
  282.             PtrArray[1] := HitWPtr;
  283.             InsertWPtr := TRUE;
  284.             end
  285.         else begin
  286.             ctr := 0;
  287.             REPEAT
  288.                 ctr := ctr + 1;
  289.                 match := (HitWPtr = PtrArray[ctr]);
  290.             UNTIL (ctr = NumWind) or (match);
  291.  
  292.             if (match)
  293.                 then InsertWPtr := FALSE
  294.                 else begin
  295.                     NumWind := NumWind + 1;
  296.                     InsertWPtr := TRUE;
  297.  
  298.                     HiPtr := PtrArray[1];
  299.                     cWPtr := HitWPtr;
  300.                     REPEAT
  301.                         cWPeek := WindowPeek (cWPtr);
  302.                         cWPtr := windowPtr(cWPeek^.nextWindow);
  303.                     UNTIL (cWPtr = HiPtr) or (cWPtr = NIL);
  304.                     if (cWPtr = HiPtr)
  305.                         then begin
  306.                             PtrArray[NumWind] := HiPtr;
  307.                             PtrArray[1] := HitWPtr;
  308.                             end
  309.                         else PtrArray[NumWind] := HitWPtr;
  310.                     end;
  311.             end;
  312. END;
  313.  
  314.  
  315. PROCEDURE SumWRgnsBelow (StartWPtr: windowPtr; DragRegion: RgnHandle);
  316. {    purpose     return in 'DragRegion' a region including all windows after & incl. window 'StartWPtr'    }
  317. VAR
  318.     currWPeek    : windowPeek;
  319.     PrevWPeek    : windowPeek;
  320.     currWindPtr    : WindowPtr;
  321. BEGIN
  322.     currWindPtr := StartWPtr;
  323.     REPEAT
  324.         currWPeek := WindowPeek (currWindPtr);
  325.         UnionRgn (currWPeek^.StrucRgn, DragRegion, DragRegion);
  326.         PrevWPeek := currWPeek;
  327.         currWindPtr := windowPtr(PrevWPeek^.nextWindow);
  328.     UNTIL (currWindPtr = NIL);
  329. END;
  330.  
  331.  
  332.  
  333. PROCEDURE MoveWindBelow (StartWPtr    : windowPtr;
  334.                                              hor, ver        : integer;
  335.                                              dragArea        : rect);
  336. {    purpose      move windows -> 'StartWPtr' to last window in the window list by 'hor','ver'    }
  337. VAR
  338.     PrevWPeek    : windowPeek;
  339.     currWindPtr    : WindowPtr;
  340.     origLoc            : point;
  341.     leftBound        : integer;
  342. BEGIN
  343.     currWindPtr := StartWPtr;
  344.     REPEAT
  345.         SetPort (grafPtr(currWindPtr));
  346.         origLoc := currWindPtr^.portrect.topleft;
  347.         LocalToGlobal (origLoc);
  348.         origLoc.h := origLoc.h + hor;
  349.         origLoc.v := origLoc.v + ver;
  350.         IF (origLoc.v < dragArea.top)
  351.             then origLoc.v := dragArea.top;
  352.         if (origLoc.v > dragArea.bottom)
  353.             then origLoc.v := dragArea.bottom;
  354.         leftBound := dragArea.left - GrafPtr(currWindPtr)^.portRect.right
  355.                                                                     + GrafPtr(currWindPtr)^.portRect.left;
  356.         if (origLoc.h < leftBound)
  357.             then origLoc.h := leftBound;
  358.         if (origLoc.h > dragArea.right)
  359.             then origLoc.h := dragArea.right;
  360.         MoveWindow(currWindPtr, origLoc.h, origLoc.v, FALSE);
  361.         PrevWPeek := WindowPeek(currWindPtr);
  362.         currWindPtr := windowPtr(PrevWPeek^.nextWindow);
  363.     UNTIL (currWindPtr = NIL);
  364. END;
  365.  
  366.  
  367.  
  368. PROCEDURE MoveWindSel (VAR PtrArray    : WindArray;
  369.                                          NumWind            : integer;
  370.                                          hor, ver            : integer;
  371.                                          dragArea            : rect);
  372. {    purpose      move windows in list 'PtrArray' by 'hor' & 'ver'    }
  373. VAR
  374.     origLoc        : point;
  375.     index        : integer;
  376.     leftBound    : integer;
  377. BEGIN
  378.     FOR index := 1 to NumWind DO begin
  379.         SetPort (grafPtr(PtrArray[index]));
  380.         origLoc := PtrArray[index]^.portrect.topleft;
  381.         LocalToGlobal (origLoc);
  382.         origLoc.h := origLoc.h + hor;
  383.         origLoc.v := origLoc.v + ver;
  384.         IF (origLoc.v < dragArea.top)
  385.             then origLoc.v := dragArea.top;
  386.         if (origLoc.v > dragArea.bottom)
  387.             then origLoc.v := dragArea.bottom;
  388.         leftBound := dragArea.left - GrafPtr(PtrArray[index])^.portRect.right
  389.                                                                     + GrafPtr(PtrArray[index])^.portRect.left;
  390.         if (origLoc.h < leftBound)
  391.             then origLoc.h := leftBound;
  392.         if (origLoc.h > dragArea.right)
  393.             then origLoc.h := dragArea.right;
  394.         MoveWindow (PtrArray[index], origLoc.h, origLoc.v, FALSE);
  395.         end;
  396. END;
  397.  
  398.  
  399.  
  400. END.
  401.  
  402.